package com.atguigu.yuntai.monitor.sql;

import com.atguigu.yuntai.monitor.bean.RuleInfoComputeWrapper;
import com.atguigu.yuntai.monitor.entity.RuleInfoCompute;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * <p>SQL的构建器</p>
 *
 **/
@Slf4j
public class SqlBuilder {


    private final StringBuilder sql = new StringBuilder();

    public void select() {
        sql.append("select ");
    }

    /**
     * 通过反射方式为sql的select子句增加字段
     * @param database hive数据库名
     * @param tableName hive表名
     * @param where where子句内容
     * @param ruleInfoComputeWrapperList 规则计算信息的包装类
     */
    public SqlBuilder(String database, String tableName, String where, List<RuleInfoComputeWrapper> ruleInfoComputeWrapperList) {
        Class<? extends SqlBuilder> thisClass = getClass();
        select();
        for (RuleInfoComputeWrapper ruleInfoComputeWrapper : ruleInfoComputeWrapperList) {
            RuleInfoCompute ruleInfoCompute = ruleInfoComputeWrapper.getRuleInfoCompute();
            String fieldsName = ruleInfoCompute.getFieldsName();
            Method method = null;
            try {
                // 表级拿无参方法，字段级拿有参方法
                if("table".equals(ruleInfoCompute.getRuleLevel())){
                    method = thisClass.getMethod(ruleInfoCompute.getCalculateType());
                    method.invoke(this);
                } else {
                    method = thisClass.getMethod(ruleInfoCompute.getCalculateType(), String.class);
                    method.invoke(this,fieldsName);
                }
            } catch (NoSuchMethodException e) {
                log.error("没有"+ruleInfoCompute.getCalculateType()+"方法",e);
                e.printStackTrace();
            } catch (InvocationTargetException | IllegalAccessException e) {
                log.error("调用"+ruleInfoCompute.getCalculateType()+"方法失败",e);
                e.printStackTrace();
            }
        }
        from(database, tableName);
        where(where);
    }

    /**
     * 总行数
     */
    public SqlBuilder countAll() {
        sql.append("count(1),");
        return this;
    }



    /**
     * 某列的空值率
     */
    public SqlBuilder nvlRate(String colName) {
        sql
                .append("(count(1) - count(")
                .append(colName)
                .append("))/count(1) ,")
                ;
        return this;
    }

    /**
     * 某列的重复率
     * @param colNames
     * @return
     */
    public SqlBuilder repeatRate(String colNames) {
        sql
                .append("1 - count(DISTINCT ")
                .append(colNames)
                .append(")/count(*),")
                ;
        return this;
    }

    /**
     * 求和
     */
    public SqlBuilder sum(String colName) {
        sql
                .append("sum(")
                .append(colName)
                .append("),")
                ;
        return this;
    }

    /**
     * 平均值
     */
    public SqlBuilder avg(String colName) {
        sql
                .append("avg(")
                .append(colName)
                .append("),")
                ;
        return this;

    }

    /**
     * 最大值
     */
    public SqlBuilder max(String colName) {
        sql
                .append("max(")
                .append(colName)
                .append("),")
                ;
        return this;
    }

    /**
     * 最小值
     */
    public SqlBuilder min(String colName) {
        sql
                .append("min(")
                .append(colName)
                .append("),")
                ;
        return this;
    }

    /**
     * 加入from语句
     */
    public SqlBuilder from(String dbName, String tableName) {
        // 移除sql语句的最后一个逗号
        if(',' == sql.charAt(sql.length()-1)){
            sql.deleteCharAt(sql.length()-1);
        }
        sql.append(" from ")
                .append(dbName)
                .append('.')
                .append(tableName)
                .append(" ")
        ;
        return this;
    }


    public SqlBuilder where(String where) {
        sql.append("where ")
                .append(where)
                ;
        return this;
    }


    public String build() {
        return sql.toString();
    }

}
